// ============================== 导入依赖 ============================== //

import axios from 'axios'

// ============================== 导出 AXIOS 工具 ============================== //

export default {
  /**
   * POST 请求
   *
   * @param {String} TIP     提示
   * @param {String} path    路径
   * @param {Object} params  参数
   * @param {Object} options 配置
   * @param {String} dataKey 数据键名 (如 data.data 返回 resp.data.data，又如 '' 直接返回 resp)
   *
   * @returns {Object} data  数据
   */
  async post(TIP, path, params = {}, options = {}, dataKey = 'data') {
    const { beginTime, headers, param } = prepare(params, this) // 准备数据
    try {
      const resp = await axios.post(path, param, { headers, ...options }) // 远程调用
      return success(TIP, param, resp, this, beginTime, dataKey) // 返回成功
    } catch (err) {
      throw error(TIP, param, err, this, beginTime) // 抛出错误
    }
  },

  /**
   * GET 请求
   *
   * @param {String} TIP     提示
   * @param {String} path    路径
   * @param {Object} params  参数
   * @param {Object} options 配置
   * @param {String} dataKey 数据键名
   *
   * @returns {Object} data  数据
   */
  async get(TIP, path, params = {}, options = {}, dataKey = 'data') {
    const { beginTime, headers, param } = prepare(params, this) // 准备数据
    try {
      const resp = await axios.get(path, { params: param, headers, ...options }) // 远程调用
      return success(TIP, param, resp, this, beginTime, dataKey) // 返回成功
    } catch (err) {
      throw error(TIP, param, err, this, beginTime) // 抛出错误
    }
  },

  /**
   * PUT 请求
   *
   * @param {String} TIP     提示
   * @param {String} path    路径
   * @param {Object} params  参数
   * @param {Object} options 配置
   * @param {String} dataKey 数据键名
   *
   * @returns {Object} data  数据
   */
  async put(TIP, path, params = {}, options = {}, dataKey = 'data') {
    const { beginTime, headers, param } = prepare(params, this) // 准备数据
    try {
      const resp = await axios.put(path, param, { headers, ...options }) // 远程调用
      return success(TIP, param, resp, this, beginTime, dataKey) // 返回成功
    } catch (err) {
      throw error(TIP, param, err, this, beginTime) // 抛出错误
    }
  },

  /**
   * DELETE 请求
   *
   * @param {String} TIP     提示
   * @param {String} path    路径
   * @param {Object} params  参数
   * @param {Object} options 配置
   * @param {String} dataKey 数据键名
   *
   * @returns {Object} data  数据
   */
  async delete(TIP, path, params = {}, options = {}, dataKey = 'data') {
    const { beginTime, headers, param } = prepare(params, this) // 准备数据
    try {
      const resp = await axios.delete(path, { params: param, headers, ...options }) // 远程调用
      return success(TIP, param, resp, this, beginTime, dataKey) // 返回成功
    } catch (err) {
      throw error(TIP, param, err, this, beginTime) // 抛出错误
    }
  },
}

// ============================== 内部方法 ============================== //

const transTIP = (TIP) => TIP.replace(/^【.*】 /, '')

/**
 * 准备数据
 *
 * @param {Object} params 参数
 * @param {Object} CORE   内核
 *
 * @returns 对象
 */
const prepare = (params, CORE) => {
  const beginTime = Date.now() // 开始时间戳
  const headers = CORE.AXIOS.headers() // 动态请求头
  if (CORE.isFormData(params) || CORE.isArray(params)) return { beginTime, headers, param: params } // 使用原始参数
  return { beginTime, headers, param: { ...CORE.AXIOS.COMMON_PARAM, ...params } } // 使用合并参数
}

/**
 * 成功
 *
 * @param {String} TIP     提示
 * @param {Object} params  参数
 * @param {Object} resp    响应
 * @param {Object} CORE    内核
 * @param {Number} time    时间戳
 * @param {String} dataKey 数据键 (如 data.data 返回 resp.data.data，又如 '' 直接返回 resp)
 *
 * @returns {Object} data  数据
 */
const success = (TIP, params, resp, CORE, time, dataKey) => {
  const times = Date.now() - time
  const { status, data } = resp || {}

  // 响应码错误
  if (status !== 200) {
    CORE.logError(TIP, params, resp, times)

    CORE.AXIOS.catchError && CORE.AXIOS.catchError(resp, CORE) // 全局的捕获异常

    const msgErr = `${transTIP(TIP)}：请求异常`
    throw new Error(msgErr)
  }

  const { code, tip, msg, err } = data.comResp || data.comresp || data || {}

  // 返回码错误
  if (code !== CORE.AXIOS.SUCCESS) {
    CORE.logWarn(TIP, params, data, times)

    CORE.AXIOS.failResp && CORE.AXIOS.failResp(data, CORE) // 全局的失败响应

    const msgErr = `${transTIP(TIP)}：${tip || msg || err || '未知错误'}`
    throw new Error(msgErr)
  }

  CORE.logInfo(TIP, params, data, times)

  if (!dataKey || !data[dataKey]) return data

  return dataKey.split('.').reduce((obj, key) => obj[key], data)
}

/**
 * 错误
 *
 * @param {String} TIP     提示
 * @param {Object} params  参数
 * @param {Error}  err     错误
 * @param {Object} CORE    内核
 * @param {Number} time    时间戳
 *
 * @returns {Object} Error 异常
 */
const error = (TIP, params, err, CORE, time) => {
  if (err.message.includes(TIP)) return err // success 中抛出的异常

  CORE.AXIOS.catchError && CORE.AXIOS.catchError(err, CORE) // 全局的捕获异常

  const times = Date.now() - time
  CORE.logError(TIP, params, err, times) // 异常日志

  const msgErr = (err.message || '异常')
    .replace('Http response at 400 or 500 level', '服务未启动')
    .replace('Network Error', '网络异常')
  return new Error(`${transTIP(TIP)}：${msgErr}`) // 返回异常
}
